// SPDX-FileCopyrightText: Copyright 2025-2025 深圳市同心圆网络有限公司
// SPDX-License-Identifier: GPL-3.0-only

package config_cmd

import (
	"fmt"
	"os"
	"os/user"
	"path/filepath"
	"strings"
	"syscall"

	"gitcode.com/openseaotter/so_agent/config"
	"gitcode.com/openseaotter/so_agent/utils"
	"gitcode.com/openseaotter/so_proto_gen_go.git/watch_api"
	"github.com/dchest/uniuri"
	"github.com/spf13/cobra"
)

var addWatchCmd_ServerAddr string

var addWatchCmd = &cobra.Command{
	Use: "addWatch",
	PreRunE: func(cmd *cobra.Command, args []string) error {
		if len(args) != 3 {
			return fmt.Errorf("need param [watch id] [secret] [script file]")
		}
		return nil
	},
	RunE: func(cmd *cobra.Command, args []string) error {
		//检查是否是root用户
		curUser, err := user.Current()
		if err != nil {
			return err
		}
		if curUser.Uid != "0" {
			return fmt.Errorf("need root to run this command")
		}

		watchId := args[0]
		secret := args[1]
		scriptFile := args[2]

		//检查script file是否存在和可执行
		scriptFile, err = filepath.Abs(scriptFile)
		if err != nil {
			return err
		}
		st, err := os.Stat(scriptFile)
		if err != nil {
			return err
		}
		if st.Mode().Perm()&0100 == 0 {
			return fmt.Errorf("script file not executable")
		}

		conn, err := utils.ConnGrpcServer(addWatchCmd_ServerAddr)
		if err != nil {
			return err
		}
		defer conn.Close()

		client := watch_api.NewWatchAgentApiClient(conn)

		timeRes, err := client.GetTime(cmd.Context(), &watch_api.AgentGetTimeRequest{})
		if err != nil {
			return err
		}
		randomStr := uniuri.NewLenChars(32, []byte("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"))
		signStr := utils.GenSign(timeRes.TimeStamp, randomStr, secret)
		getRes, err := client.GetWatchInfo(cmd.Context(), &watch_api.AgentGetWatchInfoRequest{
			WatchId:   watchId,
			TimeStamp: timeRes.TimeStamp,
			RandomStr: randomStr,
			Sign:      signStr,
		})
		if err != nil {
			return err
		}
		if getRes.Code != watch_api.AgentGetWatchInfoResponse_CODE_OK {
			return fmt.Errorf("%s", getRes.ErrMsg)
		}
		fmt.Printf("watch images %s change\n", strings.Join(getRes.Info.FullImageNameList, ","))

		//更新配置文件
		cfg, err := config.ReadAgentConfig()
		if err != nil {
			return err
		}
		cfgIndex := -1
		for index, watchCfg := range cfg.WatchCfgList {
			if watchCfg.WatchId == watchId {
				cfgIndex = index
				break
			}
		}
		newWatchCfg := config.WatchConfig{
			WatchId:    watchId,
			ServerAddr: addWatchCmd_ServerAddr,
			Secret:     secret,
			ScriptFile: scriptFile,
		}
		if cfgIndex == -1 {
			cfg.WatchCfgList = append(cfg.WatchCfgList, newWatchCfg)
		} else {
			cfg.WatchCfgList[cfgIndex] = newWatchCfg
		}
		//写入配置
		err = config.WriteAgentConfig(cfg)
		if err != nil {
			return err
		}
		fmt.Println("add watch config success")

		pid, err := utils.LoadPid()
		if err == nil {
			p, err := os.FindProcess(pid)
			if err == nil {
				p.Signal(syscall.SIGHUP)
				fmt.Println("send SIGHUP to process")
			}
		}

		return nil
	},
}

func init() {
	addWatchCmd.Flags().StringVar(&addWatchCmd_ServerAddr, "serverAddr", "", "seaotter server addr")
	addWatchCmd.MarkFlagRequired("serverAddr")
}
